/*
 *  Copyright (C) 2010 glauco
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.application;

import org.balisunrise.annotation.ActionMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.balisunrise.annotation.VisualEntity;
import org.balisunrise.common.ActionProvider;
import org.balisunrise.common.defaults.DefaultActionProvider;

/**
 * Esta classe contém os mapas de eventos do sistema e também disponibiliza
 * os eventos para as Entidades Visuais e outros compenentes VEA que utilizam
 * eventos.
 * 
 * @author Glauco
 */
public class ActionMapManager {

    /**
     * mapas de eventos.
     * A Chave é a Classe da Entidade.
     * Os Valores são listas de classes do mapas de ações.
     */
    private Map<Class,List<Class>> actionMaps = new HashMap<Class,List<Class>>();

    /**
     * Providers das classes
     */
    private Map<Class,DefaultActionProvider> providers =
            new HashMap<Class, DefaultActionProvider>();

    /**
     * Adiciona um ActionMap.
     * Estas classes devem ter a annotation ActionMap.
     * @param actionMap classe da ActionMap
     * @see org.balisunrise.annotation.ActionMap
     */
    public void putActionMap(Class actionMap){

        if (!actionMap.isAnnotationPresent(ActionMap.class))
            return ;
            
        ActionMap annotation = 
                (ActionMap) actionMap.getAnnotation(ActionMap.class);
        for (Class entityClass : annotation.classes()) {
            putActionMap(entityClass, actionMap);
        }
    }

    /**
     * Adiciona um ActionMap.
     * @param entityClass classe da entidade do mapa de eventos.
     * @param actionMap classe do mapa de ações.
     */
    public void putActionMap(Class entityClass, Class actionMap){
        if (actionMaps.containsKey(entityClass)){
            List<Class> evts = actionMaps.get(entityClass);
            if(!evts.contains(actionMap))
                evts.add(actionMap);
        }else{
            List<Class> evts = new ArrayList<Class>();
            evts.add(actionMap);
            actionMaps.put(entityClass, evts);
        }
        if (providers.containsKey(entityClass))
            providers.get(entityClass).addActionMap(actionMap);
    }

    /**
     * Adiciona os Mapas de Ações de uma entidade com annotation VisualEntity.
     * @param entityClass classe da entidade.
     * @see org.balisunrise.annotation.VisualEntity
     */
    public void putEntityActionMaps(Class entityClass){

        if(!entityClass.isAnnotationPresent(VisualEntity.class))
            return ;

        VisualEntity ve = (VisualEntity)
                entityClass.getAnnotation(VisualEntity.class);
        for (Class actionMap : ve.actionMaps()) {
            putActionMap(entityClass, actionMap);
        }
    }

    /**
     * Retorna as Classes dos mapas de ações de uma entidade.
     * Caso não encontre nenhum mapa de ações é retornado um array vazio.
     * @param entityClass entidade
     * @return array de classes de mapa de ações.
     */
    public Class[] getActionMaps(Class entityClass){

        if(actionMaps.containsKey(entityClass)){
            List<Class> list = actionMaps.get(entityClass);
            return list.toArray(new Class[list.size()]);
        }

        return new Class[0];
    }

    /**
     * Retorna um Provedor de Action para a classe da entidade.
     * Retorna um Provedor vazio se não exitir mapas de ações para a entidade.
     * @param entityClass Classe da entidade dos eventos.
     * @return Um ActionProvider
     */
    public ActionProvider getActionProvider(Class entityClass){

        if (providers.containsKey(entityClass))
            return providers.get(entityClass);

        List<Class> classes = actionMaps.get(entityClass);
        DefaultActionProvider ep = new DefaultActionProvider(entityClass);

        if(classes != null)
            ep.setActionMaps(classes);

        providers.put(entityClass, ep);
        
        return ep;
    }
}
